﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace APMDemo
{
    class ContinuationDemo
    {
        //static async Task Main(string[] args)
        //{
        //    DoCaculate();
        //    //await DoCaculateAsync();
        //    Console.ReadLine();
        //}
        // 使用awaiter
        static void DoCaculate()
        {
            long total = 0;
            long[] numbers = new long[5] { 100000000, 200000000, 500000000, 600000000, 700000000 };
            foreach (long number in numbers)
            {
                long result = 0;
                var task = DoSum(number);
                // 使用task.GetAwaiter()方法获取一个用于等待该task执行完毕的awaiter对象
                // DoSum(number).GetAwaiter()
                var awaiter = task.GetAwaiter();
                // awaiter.OnCompleted()中专递的委托事件就是一个continiuation,表示awaiter对应的task执行完毕（或异常时）后的后续操作
                // continiuation可以捕获当前线程中的变量值，并使用awaiter.GetResult()获取task的返回结果
                awaiter.OnCompleted(() =>
                {
                    // 使用awaiter.GetResult()获取task的返回结果
                    // 如果执行Task发生异常，在使用 awaiter.GetResult() 时将会直接把异常抛出
                    result = awaiter.GetResult();
                    total += result;
                    Console.WriteLine("OnCompleted done!");
                });
                // 等待task执行完毕
                // Wait() 适合用于单一 Task 对象，如果想操作一组对象，可采用 Task 的两个静态方法 Task.WaitAll() 和 Task.WaitAny() 。
                task.Wait();
                Console.WriteLine($"1+...+{number} = {result}");

                // 使用 task.Result 获取 task 返回结果，同上述效果相同
                //Console.WriteLine($"1+...+{number} = {task.Result}");


                // 另一种方式：使用task.ContinuWith()
                // ContinueWith 返回一个Taskd对象，可以附加更多的continuation
                // ContinueWith 的参数接收的Task就是 调用ContinueWith 的Task
                Task<long> continueTask = task.ContinueWith(tsk =>
                {
                    try
                    {
                        // 获取task的结果
                        result = tsk.Result;

                        Console.WriteLine("Task ContinueWith done!");
                        // 返回结果,被包装成Task<T>，如果返回值，则结果被包装成Task
                        return result * 10;
                    }
                    catch (AggregateException ex) // ContinueWith中吧异常封装为AggregateException，如果处理异常必须直接处理AggregateException
                    {
                        throw ex;
                    }

                });
            }

            Console.WriteLine($"合计 = {total}");
        }

        /// <summary>
        /// 异步方法，使用 async/await
        /// </summary>
        /// <returns></returns>
        static async Task DoCaculateAsync()
        {
            long[] numbers = new long[5] { 100000000, 200000000, 500000000, 600000000, 700000000 };
            foreach (long number in numbers)
            {
                // await表达式
                long result = await DoSum(number);
                Console.WriteLine($"1+...+{number} = {result}");
            }
        }

        static Task<long> DoSum(long number)
        {
            return Task.Run(() =>
            {
                long sum = 0;
                for (long i = 1; i <= number; i++)
                {
                    sum += i;
                }
                Console.WriteLine("DoSum done !!!");
                return sum;
            });
        }
    }
}
